// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-11-19

package tracer

import (
	"gitee.com/go-libs/log/base"
	"gitee.com/go-libs/log/common"
	"gitee.com/go-libs/log/conf"
	"gitee.com/go-libs/log/logger"
	"gitee.com/go-libs/log/tracer/disabled"
	"gitee.com/go-libs/log/tracer/jaeger_plugin"
	"gitee.com/go-libs/log/tracer/zipkin_plugin"
	"sync"
)

var (
	once      = new(sync.Once)
	singleton common.SpanManager
)

type manager struct {
	bucket common.Bucket[common.Span]
	mu     *sync.RWMutex
	plugin common.SpanPlugin
}

// New
// 管理器单例.
func New() common.SpanManager {
	return singleton
}

// GetPlugin
// 读取插件实例.
func (o *manager) GetPlugin() (plugin common.SpanPlugin) {
	o.mu.RLock()
	plugin = o.plugin
	o.mu.RUnlock()
	return
}

// Send
// 上报数据.
func (o *manager) Send(span common.Span) {
	// 1. 复制日志.
	if list := span.GetLogs(); len(list) > 0 {
		x := logger.New()
		for _, v := range list {
			x.Send(v.Copy())
		}
	}

	// 2. 数据入桶.
	o.bucket.Add(span)
}

// SetPlugin
// 设置插件实例.
func (o *manager) SetPlugin(plugin common.SpanPlugin) {
	if plugin != nil {
		o.mu.Lock()
		o.plugin = plugin
		o.mu.Unlock()
	}
}

// Wait
// 等待完成.
func (o *manager) Wait() {
	o.bucket.Stop().Wait()
}

// +------------------------------------------------------------------------------+
// | Access methods                                                               |
// +------------------------------------------------------------------------------+

func (o *manager) do(spans ...common.Span) {
	var err error

	// 1. 监听结束.
	defer func() {
		// 捕获异常.
		if r := recover(); r != nil {
			common.Debugger.Fatal("tracer.manager.do panic: %v", r)
		}

		// 输出错误.
		if err != nil {
			common.Debugger.Fatal("tracer.manager.do error: %v", err)
		}

		// 释放回池.
		for _, v := range spans {
			v.Release()
		}
	}()

	// 2. 调用插件.
	err = o.plugin.Report(spans)
}

func (o *manager) init() *manager {
	o.mu = &sync.RWMutex{}
	return o.initPlugin().initBucket()
}

func (o *manager) initBucket() *manager {
	o.bucket = common.NewBucket[common.Span]("tracer", o.do)
	o.bucket.Start()
	return o
}

func (o *manager) initPlugin() *manager {
	// 1. 插件适配.
	switch conf.New().Tracer {
	case base.TracerJaeger:
		o.plugin = jaeger_plugin.New()
	case base.TracerZipkin:
		o.plugin = zipkin_plugin.New()
	default:
		o.plugin = disabled.New()
	}

	// 2. 输出模式.
	return o
}

func init() {
	once.Do(func() {
		singleton = (&manager{}).init()
	})
}
